﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using Models;

namespace WebApp.Controllers
{
    [Authorize]
    public class ClientProfileController : Controller
    {
        private AccufindCMSEntities db = new AccufindCMSEntities();
        private static char accufindTaggingInfoDelimiter = '|';

        // GET: ClientProfile
        public ActionResult Index()
        {
            var clientProfiles = db.ClientProfiles.Include(c => c.Gender).Include(c => c.Race);
            return View(clientProfiles.ToList());
        }

        // GET: ClientProfile/Details/5
        public ActionResult Details(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            ClientProfile clientProfile = db.ClientProfiles.Find(id);
            if (clientProfile == null)
            {
                return HttpNotFound();
            }
            return View(clientProfile);
        }

        // GET: ClientProfile/Create
        public ActionResult Create()
        {
            PrepareAccufindTaggingInfoViewData(ViewBag);
            ViewBag.GenderId = new SelectList(db.Genders, "GenderId", "Name");
            ViewBag.RaceId = new SelectList(db.Races, "RaceId", "Name");
            return View();
        }

        // POST: ClientProfile/Create
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create([Bind(Include = "ClientProfileId,Name,NRIC,GenderId,RaceId,Age,FamilyContactNo,MedicalCondition")] ClientProfile clientProfile, string AccufindTaggingInfoIdentifier)
        {
            if (ModelState.IsValid)
            {
                ClientProfile profile = db.ClientProfiles.Add(clientProfile);
                db.SaveChanges();

                AddAccufindTags(AccufindTaggingInfoIdentifier, profile.ClientProfileId);

                return RedirectToAction("Index");
            }

            PrepareAccufindTaggingInfoViewData(ViewBag);
            ViewBag.GenderId = new SelectList(db.Genders, "GenderId", "Name", clientProfile.GenderId);
            ViewBag.RaceId = new SelectList(db.Races, "RaceId", "Name", clientProfile.RaceId);
            return View(clientProfile);
        }

        // GET: ClientProfile/Edit/5
        public ActionResult Edit(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            ClientProfile clientProfile = db.ClientProfiles.Find(id);
            if (clientProfile == null)
            {
                return HttpNotFound();
            }
            PrepareAccufindTaggingInfoViewData(ViewBag);
            ViewBag.GenderId = new SelectList(db.Genders, "GenderId", "Name", clientProfile.GenderId);
            ViewBag.RaceId = new SelectList(db.Races, "RaceId", "Name", clientProfile.RaceId);
            return View(clientProfile);
        }

        // POST: ClientProfile/Edit/5
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit([Bind(Include = "ClientProfileId,Name,NRIC,GenderId,RaceId,Age,FamilyContactNo,MedicalCondition")] ClientProfile clientProfile, string AccufindTaggingInfoIdentifier)
        {
            if (ModelState.IsValid)
            {
                db.Entry(clientProfile).State = EntityState.Modified;
                db.SaveChanges();
                
                if (!string.IsNullOrWhiteSpace(AccufindTaggingInfoIdentifier))
                {
                    RemoveAllAccufindTags(clientProfile.ClientProfileId);

                    AddAccufindTags(AccufindTaggingInfoIdentifier, clientProfile.ClientProfileId);

                    RemoveUnusedTagsUniversally();
                }
                return RedirectToAction("Index");
            }
            PrepareAccufindTaggingInfoViewData(ViewBag);
            ViewBag.GenderId = new SelectList(db.Genders, "GenderId", "Name", clientProfile.GenderId);
            ViewBag.RaceId = new SelectList(db.Races, "RaceId", "Name", clientProfile.RaceId);
            return View(clientProfile);
        }

        // GET: ClientProfile/Delete/5
        public ActionResult Delete(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            ClientProfile clientProfile = db.ClientProfiles.Find(id);
            if (clientProfile == null)
            {
                return HttpNotFound();
            }
            return View(clientProfile);
        }

        // POST: ClientProfile/Delete/5
        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public ActionResult DeleteConfirmed(int id)
        {
            ClientProfile clientProfile = db.ClientProfiles.Find(id);
            if (clientProfile != null)
            {
                RemoveAllAccufindTags(id);
                RemoveUnusedTagsUniversally();
            }
            db.ClientProfiles.Remove(clientProfile);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                db.Dispose();
            }
            base.Dispose(disposing);
        }

        private void PrepareAccufindTaggingInfoViewData(dynamic viewBag)
        {
            viewBag.AllAccufindTaggingInfoTags = string.Join(accufindTaggingInfoDelimiter.ToString(), db.AccufindTaggingInfoes.Select(t => t.Name));
            viewBag.TagDelimiter = accufindTaggingInfoDelimiter.ToString();
        }

        private void AddAccufindTags(string accufindTaggingInfoIdentifier, int profileId)
        {
            if (!string.IsNullOrWhiteSpace(accufindTaggingInfoIdentifier))
            {
                ClientProfile profile = db.ClientProfiles.Include(p => p.AccufindTaggingInfoes).FirstOrDefault(p => p.ClientProfileId == profileId);
                if (profile != null)
                {
                    //if (profile.AccufindTaggingInfoes == null)
                    //{
                    //    profile.AccufindTaggingInfoes = new List<AccufindTaggingInfo>();
                    //}

                    string value = "";
                    foreach (string tagString in accufindTaggingInfoIdentifier.Split(accufindTaggingInfoDelimiter))
                    {
                        value = tagString.Trim();
                        AccufindTaggingInfo tag = db.AccufindTaggingInfoes.FirstOrDefault(t => t.Name == value);
                        if (tag == null)
                        {
                            tag = new AccufindTaggingInfo();
                            tag.Name = value;
                            tag = db.AccufindTaggingInfoes.Add(tag);
                            db.SaveChanges();
                        }
                        profile.AccufindTaggingInfoes.Add(tag);
                        db.SaveChanges();
                    }
                }
            }
        }

        private void RemoveAllAccufindTags(int profileId)
        {
            ClientProfile profile = db.ClientProfiles.Include(p => p.AccufindTaggingInfoes).FirstOrDefault(p => p.ClientProfileId == profileId);
            if (profile != null)
            {
                var tagCollection = profile.AccufindTaggingInfoes;
                if (tagCollection != null)
                {
                    while (tagCollection.Count() > 0)
                    {
                        tagCollection.Remove(tagCollection.First());
                    }
                    db.SaveChanges();
                }
            }
        }

        private void RemoveUnusedTagsUniversally()
        {
            List<long> usedTagIds = db.ClientProfiles
                                        .SelectMany(p => p.AccufindTaggingInfoes
                                            .Select(t => t.AccufindTaggingInfoId))
                                            .ToList();

            db.AccufindTaggingInfoes.RemoveRange(db.AccufindTaggingInfoes.Where(u => !usedTagIds.Contains(u.AccufindTaggingInfoId)));
            db.SaveChanges();
        }
    }
}
